package be.android.forap.dataprovider;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Security;
import java.util.UUID;

import org.json.JSONObject;
import org.spongycastle.jce.provider.BouncyCastleProvider;
import android.provider.BaseColumns;
import android.text.TextUtils;
import android.util.Log;

public class RawContact implements BaseColumns{

	private static final String TAG = "Contact";

	private final String mFullName;
	private final String mFirstName;
	private final String mLastName;
	private final String mCellPhone;
	private final String mEmail;

	private final boolean mDeleted;
	private final boolean mDirty;
	
	private final String mGlobalContactId;
	private final long mRawContactId;

	private String mPublicKeyBlock;
	
	private long mSyncState;

	// Will be used by the ArrayAdapter in the ListView
	@Override
	public String toString() {
		//TODO
		return mFirstName +" " +mLastName;
	}

	public String getPublicKeyBlock() {
		return mPublicKeyBlock;
	}

	public String getGlobalContactId() {
		return mGlobalContactId;
	}

	public long getRawContactId() {
		return mRawContactId;
	}

	public String getFirstName() {
		return mFirstName;
	}

	public String getLastName() {
		return mLastName;
	}

	public String getFullName() {
		return mFullName;
	}

	public String getCellPhone() {
		return mCellPhone;
	}

	public String getEmail() {
		return mEmail;
	}

	public boolean isDeleted() {
		return mDeleted;
	}

	public boolean isDirty() {
		return mDirty;
	}
	
	public long getSyncState(){
		return mSyncState;
	}

	public String getBestName() {
		if (!TextUtils.isEmpty(mFullName)) {
			return getFullName();
		} else if (TextUtils.isEmpty(mFirstName)) {
			return mLastName;
		} else {
			return mFirstName;
		}
	}


	/**
	 * Convert the RawContact object into a JSON string.  From the
	 * JSONString interface.
	 * @return a JSON string representation of the object
	 */
	public JSONObject toJSONObject() {
		JSONObject json = new JSONObject();

		try {
			if (!TextUtils.isEmpty(mFullName)) {
				json.put("n", mFullName);
			}
			if (!TextUtils.isEmpty(mFirstName)) {
				json.put("f", mFirstName);
			}
			if (!TextUtils.isEmpty(mLastName)) {
				json.put("l", mLastName);
			}
			if (!TextUtils.isEmpty(mCellPhone)) {
				json.put("m", mCellPhone);
			}
			if (!TextUtils.isEmpty(mEmail)) {
				json.put("e", mEmail);
			}
			if (!TextUtils.isEmpty(mPublicKeyBlock)) {
				json.put("p", mPublicKeyBlock);
			}
			if (!TextUtils.isEmpty(mGlobalContactId)) {
				json.put("i", mGlobalContactId);
			}
			/*if (mRawContactId > 0) {
				json.put("c", mRawContactId);
			}*/
			/*if (mDeleted) {
				json.put("del", mDeleted);
			}
			if (mDirty) {
				json.put("dirty", mDirty);
			}*/
			if(mSyncState > 0){
				json.put("x",mSyncState);
			}
		} catch (final Exception ex) {
			Log.i(TAG, "Error converting RawContact to JSONObject" + ex.toString());
		}

		return json;
	}

	public RawContact(String fullName, String firstName, String lastName,
			String cellPhone, String email,
			String publickey, boolean deleted, String globalContactId,
			long rawContactId, long syncState, boolean dirty) {
		mFullName = fullName;
		mFirstName = firstName;
		mLastName = lastName;
		mCellPhone = cellPhone;
		mEmail = email;
		mPublicKeyBlock = publickey;
		mDeleted = deleted;
		mGlobalContactId = globalContactId;
		mRawContactId = rawContactId;
		mSyncState = syncState;
		mDirty = dirty;
	}

	/**
	 * Creates and returns an instance of the RawContact from the provided JSON data.
	 *
	 * @param user The JSONObject containing user data
	 * @return user The new instance of Sample RawContact created from the JSON data.
	 */
	public static RawContact valueOf(JSONObject contact) {

		try {
			final String globalContactId = !contact.isNull("i") ? contact.getString("i") : null;
			//final int rawContactId = !contact.isNull("c") ? contact.getInt("c") : -1;
			final String fullName = !contact.isNull("n")  ? contact.getString("n") : null;
			final String firstName = !contact.isNull("f")  ? contact.getString("f") : null;
			final String lastName = !contact.isNull("l") ? contact.getString("l") : null;
			final String cellPhone = !contact.isNull("m") ? contact.getString("m") : null;
			final String email = !contact.isNull("e") ? contact.getString("e") : null;
			final String publickey = !contact.isNull("p") ? contact.getString("p") : null;
			//final boolean deleted = !contact.isNull("del") ? contact.getBoolean("del") : false;
			//final boolean dirty = !contact.isNull("dirty") ? contact.getBoolean("dirty") : false;
			final long syncState = !contact.isNull("x") ? contact.getLong("x") : 0;
			return new RawContact(fullName, firstName, lastName, cellPhone,
					email,publickey, false, globalContactId, -1, syncState, false);
		} catch (final Exception ex) {
			Log.i(TAG, "Error parsing JSON contact object" + ex.toString());
		}
		return null;
	}


	/**
	 * Creates and returns RawContact instance from all the supplied parameters.
	 */
	public static RawContact createNewContact(String fullName, String firstName, String lastName,
			String cellPhone,	String email, String publickey,  String globalContactId) {
		return new RawContact(fullName, firstName, lastName, cellPhone,
				email, publickey, false, globalContactId, -1,	
				-1, true);
	}
	
	/**
	 * Creates and returns RawContact instance from all the supplied parameters.
	 */
	public static RawContact createContact(String fullName, String firstName, String lastName,
			String cellPhone,	String email, String publickey, boolean deleted,
			long rawContactId, String globalContactId, boolean dirty) {
		return new RawContact(fullName, firstName, lastName, cellPhone,
				email, publickey, deleted, globalContactId, rawContactId,	
				-1, dirty);
	}

	/**
	 * Creates and returns a User instance that represents a deleted user.
	 * Since the user is deleted, all we need are the client/server IDs.
	 * @param clientUserId The client-side ID for the contact
	 * @param serverUserId The server-side ID for the contact
	 * @return a minimal User object representing the deleted contact.
	 */
	//TODO switch
	public static RawContact createDeletedContact(long rawContactId, String globalContactId){
		return new RawContact(null, null, null, null, null, null, 
				true, globalContactId, rawContactId, -1, true);
	}
	
	public boolean equals(Object o){
		//null instanceof Object will always return false
	    if (!(o instanceof RawContact))
	      return false;
		return UUID.fromString(this.getGlobalContactId()).equals(UUID.fromString(((RawContact) o).getGlobalContactId()));
	}
	
	/************************
	 * 
	 * Contact Integrity
	 * 
	 * **********************/
	
	private String digestAlgorithm = "SHA-512";
	
	public byte[] calculateIntegrityDigest() {
		byte[] digest = null;
		try {
			
			Security.addProvider(new BouncyCastleProvider());
			MessageDigest md;
			md = MessageDigest.getInstance(digestAlgorithm, "SC");
			
			String sensitiveData = getSensitiveData();
			digest = md.digest(sensitiveData.getBytes());
			
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchProviderException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return digest;
	}
	
	
	public boolean verify(byte[] test){
		byte[] digest =  calculateIntegrityDigest();
		if(digest == null || test == null)
			return false;
		return (MessageDigest.isEqual(digest,test));
	}
	
	private String getSensitiveData(){
		return mGlobalContactId + mPublicKeyBlock;
	}

}